Jx.declare('Jx.lib.Query', {

	$requires: [ 'Jx.lib.Query.Operation' ],

	$actions: [

		'exec',

		'createOperation'

	],

	$cascadeCallback: function(Class, Base){

		var cProcessors = Class.prototype.processors,

			bProcessors = Base.prototype.processors;

		if (Jx.isObject(bProcessors)){

			Jx.assignIf( cProcessors, bProcessors );

		}

	},

	parserClass: undefined,

	parser: undefined,

	parseEmpty: false,

	processors: {},

	processOperationClass: 'Jx.lib.Query.Operation',

	constructor: function(){

		this.$super();

		var parser = Jx.instantiate(this.parserClass);

		if (Jx.instanceOf(parser, 'Jx.lib.Parser')){

			this.parser = parser;

		} else {

			throw Jx.createError('Type', 'invalid parser for: ', this.constructor.$name, ' [', parser, ']');

		}

	},

	onExec: function(operation, query){

		//-- parser operation
		var parserOperation = this.createOperation.apply(this, Array.prototype.slice.call(arguments, 1)),

			parser = this.parser,

			errors;

		parserOperation.get('parser').parse( query, function(rule, lexeme){

			var processors = this.processors,

				returnValue = void(0);

			if (rule in processors){

				returnValue = processors[callback].call(this.manager, this, rule, lexeme);

			}

			return returnValue;

		}, parserOperation);

		if (parser.failed){

			var info = parser.tokenizer.getInfo();

			parserOperation.error(2, 'Parse Error at line: '+info.line+' column: ', info.column);

		}

	},

	onCreateOperation: function(operation, query){

		operation.returnValue = Jx.instantiate( this.processOperationClass, [{

			query: query,

			manager: this,

			processors: this.processors,

			parser: this.parser,

			returnValue: void(0)

		}]);

	},

	allowExec: function(operation, query){

		operation.returnValue = false;

		return Jx.isString(query, !this.parseEmpty);

	},

	allowCreateOperation: function(operation, query){

		operation.returnValue = void(0);

		return Jx.isString(query, !this.parseEmpty);

	}

});
